<?php

/**
 * PENGUIN FrameWork
 * @author hungtd <tdhungit@gmail.com> 0972014011
 * @copyright Tran Dinh Hung 2011
 * 
 * Model
 * Penguin custom
 * 
 * @package PenguinFW
 * @subpackage Core
 * @version 1.0.0
 * 
 * @property CI_Loader $load
 * @property CI_Form_validation $form_validation
 * @property CI_Input $input
 * @property CI_Email $email
 * @property CI_DB_active_record $db
 * @property CI_DB_forge $dbforge
 * @property CI_Table $table
 * @property CI_Session $session
 */

class MY_Model extends CI_Model
{

    // main table on database
    protected $db_table = '';
    // require field
    protected $required_fields = array();
    // config cache
    protected $db_cache = FALSE;

    function __construct()
    {
        parent::__construct();
    }

    /**
     * Setter/Getters for the table prop
     * @param String $table
     */
    public function setTable($table)
    {
        $this->db_table = $table;
    }

    public function getTable()
    {
        return $this->db_table;
    }

    /**
     * _required method returns false if the $data array does not contain all of the keys assigned by the $required array.
     *
     * @param array $required
     * @param array $data
     * @return bool
     */
    function _required($required, $data)
    {
        foreach ($required as $field)
        {
            if (!isset($data[$field]))
            {
                return FALSE;
            }
        }
        return TRUE;
    }

    /**
     * get list table
     *      
     * @param array $where
     * @param string $order_by
     * @return Obj / array
     */
    public function get($where = NULL, $order_by = NULL, $is_one = TRUE, $limit = 20, $offset = '')
    {
        $this->db->select('*');
        $this->db->from($this->db_table);
        
        // set where in query
        if (is_array($where))
        {
            $this->db->where($where);
        }

        // set order
        if ($order_by)
        {
            $this->db->order_by($order_by);
        }
        
        // set limit if query multi array
        if ($is_one == FALSE && is_numeric($limit) && $limit > 0)
        {            
            if ($offset)
            {
                $this->db->limit($limit, $offset);
            } else 
            {
                $this->db->limit($limit);
            }
        }

        // query in cache or no cache
        $query = $this->db_get_cache();

        // not record
        if ($query->num_rows() == 0)
        {
            return FALSE;
        }

        // get one record
        if ($is_one == TRUE)
        {
            return $query->row();
        }

        // all record
        return $query->result_array();
    }

    /**
     * Get list data width select
     * 
     * @param string $select
     * @param array $where
     * @param string $order_by
     * @return Obj / array
     */
    public function get_select($select, $where = NULL, $order_by = NULL, $is_one = TRUE, $limit = 20)
    {
        $this->db->select($select);
        $this->db->from($this->db_table);

        // get where in query
        if ($where)
        {
            $this->db->where($where);
        }

        // get order by
        if ($order_by)
        {
            $this->db->order_by($order_by);
        }
        
        // get limit
        if ($is_one == FALSE && is_numeric($limit) && $limit > 0)
        {
            if ($offset)
            {
                $this->db->limit($limit, $offset);
            } else 
            {
                $this->db->limit($limit);
            }
        }

        // query in cache or no cache
        $query = $this->db_get_cache();

        if ($query->num_rows() == 0)
        {
            return FALSE;
        }

        // get one record
        if ($is_one == TRUE)
        {
            return $query->row();
        }

        // get all record
        return $query->result_array();
    }

    /**
     * create record
     *      
     * @param array $data
     * @return int
     */
    public function create($data)
    {
        // check field require
        if (!$this->_required($this->required_fields, $data))
        {
            return FALSE;
        }

        $this->load->helper('date');

        // field default: created / modified / user_id
        $data['created'] = mdate('%Y-%m-%d %H:%i:%s', now());
        $data['modified'] = mdate('%Y-%m-%d %H:%i:%s', now());
        $data['user_id'] = $this->session->userdata('user_id');

        // insert record
        if ($this->db->insert($this->db_table, $data))
        {
            // get id
            return $this->db->insert_id();
        }

        return FALSE;
    }

    /**
     * Update record
     *      
     * @param array $data
     * @param array $where 
     */
    public function update($data, $where)
    {
        // check update record
        if (!$this->_required($this->required_fields, $data))
        {
            return FALSE;
        }

        $this->load->helper('date');

        // update date modified
        $data['modified'] = mdate('%Y-%m-%d %H:%i:%s', now());

        // update data
        $this->db->where($where);
        $this->db->update($this->db_table, $data);
    }

    /**
     * Update record is delete
     *      
     * @param array $where 
     */
    public function delete($where, $is_restore = FALSE)
    {
        $this->load->helper('date');
        
        // error params
        if (empty ($where))
        {
            return FALSE;
        }

        // update date delete and hidden record
        // is restore
        if ($is_restore == TRUE)
        {
            $data = array(
                'modified' => mdate('%Y-%m-%d %H:%i:%s', now()),
                'is_delete' => 0
            );
        } else // is delete 
        {
            $data = array(
                'modified' => mdate('%Y-%m-%d %H:%i:%s', now()),
                'is_delete' => 1
            );
        }

        $this->db->where($where);
        $this->db->update($this->db_table, $data);
    }

    /**
     * Delete record on database
     *      
     * @param array $where 
     */
    public function deleteRecord($where)
    {
        // error params
        if (empty ($where))
        {
            return FALSE;
        }
        
        $this->db->where($where);
        $this->db->delete($this->db_table, $where);
    }

    /**
     * query cache on PG
     * 
     * @return query_obj
     */
    public function db_get_cache()
    {
        if ($this->db_cache == FALSE)
        {
            $data = $this->db->get();
        } else
        {
            $this->db->cache_on();
            $data = $this->db->get();
            $this->db->cache_off();
        }

        return $data;
    }

    /**
     * Logs an error
     * 
     * @param String $level
     * @param String $msg
     */
    protected function log($level, $msg)
    {
        log_message($level, __CLASS__ . '->' . __METHOD__ . ' :: ' . $msg . ' | In: ' . __FILE__ . ' Line: ' . __LINE__);
    }

    /**
     * Checks if certain field in any row has a certain value.
     * Its used to have a unique data like username, email etc.
     * 
     * @param String $field Name of the field in the table to check the data in
     * @param String $value The value to check if exists in that field
     * @return Bool TRUE if this data exists, FALSE if unique
     */
    public function is_duplicate($fieldName, $value)
    {
        if (empty($fieldName) OR empty($value))
        {
            return FALSE;
        } else
        {
            $this->db->select($fieldName);
            $query = $this->db->get_where($this->db_table, array($fieldName => $value));
            if ($query->num_rows > 0)
            {
                return TRUE;
            } else
            {
                return FALSE;
            }
        }
        return FALSE;
    }
    
    /**
     * Query about conditions
     * 
     * @param string $type 'first', 'all', 'count'
     * @param array $options
     *  'select' => string,
     *  'join' => array(),
     *  'leftjoin' => array(),
     *  'rightjoin' => array(),
     *  'from' => string,
     *  'where' => array(),          
     *  'order' => array(),
     *  'limit' => int,
     *  'offset' => int
     * @return array
     */
    public function find($type = 'all', $options = array())
    {
        // get select -> query
        if (isset($options['select']) && $options['select'])
        {
            $this->db->select($options['select']);
        } else
        {
            $this->db->select('*');
        }
        
        // get table join
        // inner join
        if (isset($options['join']) && !empty ($options['join']))
        {            
            foreach ($options['join'] as $table => $cond)
            {                
                $this->db->join($table, $cond);
            }
        }
        
        // left join
        if (isset($options['leftjoin']) && !empty ($options['leftjoin']))
        {            
            foreach ($options['leftjoin'] as $table => $cond)
            {                
                $this->db->join($table, $cond, 'left');
            }
        }
        
        // right join
        if (isset($options['rightjoin']) && !empty ($options['rightjoin']))
        {            
            foreach ($options['rightjoin'] as $table => $cond)
            {                
                $this->db->join($table, $cond, 'right');
            }
        }
        
        // from table
        if (isset($options['from']) && $options['from']) 
        {
            $this->db->from($options['from']);
        } else 
        {
            $this->db->from($this->db_table);
        }
        
        // where
        if (isset($options['where']) && !empty ($options['where']))
        {
            $this->db->where($options['where']);
        }                
        
        // count all result query
        if ($type == 'count')
        {
            return $this->db->count_all_results();
        }
        
        // order
        if (isset($options['order']) && !empty ($options['order']))
        {
            foreach ($options['order'] as $field_order => $type_order)
            {
                $this->db->order_by($field_order, $type_order);
            }
        }
        
        // limit
        if (isset($options['limit']) && $options['limit'])
        {
            if (isset($options['offset']) && $options['offset'])
            {
                $this->db->limit($options['limit'], $options['offset']);
            } else 
            {
                $this->db->limit($options['limit']);
            }
        }
        
        // query
        $query = $this->db->get();        
        
        // get result
        if ($query->num_rows() == 0)
        {
            return array();
        }
        
        switch ($type)
        {
            case 'first':
                return $query->row();
                break;
            
            case 'all':
                return $query->result_array();
                break;            
            default:
                return array();
                break;
        }
    }

}

?>
